package com.jeeplus.modules.web.web;

import com.jeeplus.common.config.Global;
import com.jeeplus.common.json.AjaxJson;
import com.jeeplus.common.utils.DateUtils;
import com.jeeplus.common.utils.StringUtils;
import com.jeeplus.core.persistence.Page;
import com.jeeplus.core.qr.ImgQrTool;
import com.jeeplus.core.qr.QrImage;
import com.jeeplus.core.web.BaseController;
import com.jeeplus.modules.sys.entity.User;
import com.jeeplus.modules.sys.utils.UserUtils;
import com.jeeplus.modules.web.entity.YjQrcodes;
import com.jeeplus.modules.web.service.YjQrcodesService;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 二维码Controller
 * @author liangbing
 * @version 2021-03-14
 */
@Controller
@RequestMapping(value = "${adminPath}/web/yjQrcodes")
public class YjQrcodesController extends BaseController {
    @Autowired
    private YjQrcodesService yjQrcodesService;

    private final int CATEGORY_MAHJONGHALLROOM = 1;

    private static String appid = Global.getConfig("appId");// 应用ID
    private static String appsecret = Global.getConfig("appSecret");// 应用密钥
    private static final String ROOM_QRCODE_RELATIVE_PATH = Global.USERFILES_BASE_URL + "/roomqrcode/";
    private static final String roomQrcodeGeneratorPath = Global.getConfig("roomQrcodeGenerator");
    private static final String imgFilesDirPath = Global.getConfig("imgFilesDirPath");
    private static final String tempImgFolder = Global.getConfig("tempImgFolder");
    private static final String roomQrCodeFolder = Global.getConfig("roomQrCodeFolder");
    private static final String imgUrl = Global.getConfig("imgUrl");

    @ModelAttribute
    public YjQrcodes get(@RequestParam(required=false) String id) {
        YjQrcodes entity = null;
        if (StringUtils.isNotBlank(id)){
            entity = yjQrcodesService.get(id);
        }
        if (entity == null){
            entity = new YjQrcodes();
        }
        return entity;
    }

    /**
     * 二维码列表页面
     */
    @RequiresPermissions("web:yjQrcodes:list")
    @RequestMapping(value = {"list", ""})
    public String list() {
        return "modules/web/yjQrcodesList";
    }

    /**
     * 二维码列表数据
     */
    @ResponseBody
    @RequiresPermissions("web:yjQrcodes:list")
    @RequestMapping(value = "data")
    public Map<String, Object> data(YjQrcodes yjQrcodes, HttpServletRequest request, HttpServletResponse response, Model model) {
        Page<YjQrcodes> page = yjQrcodesService.findPage(new Page<YjQrcodes>(request, response), yjQrcodes);
        return getBootstrapData(page);
    }

    /**
     * 查看，增加，编辑二维码表单页面
     */
    @RequiresPermissions(value={"web:yjQrcodes:view","web:yjQrcodes:add","web:yjQrcodes:edit"},logical= Logical.OR)
    @RequestMapping(value = "form")
    public String form(YjQrcodes yjQrcodes, Model model) {
        model.addAttribute("yjQrcodes", yjQrcodes);
        if(StringUtils.isBlank(yjQrcodes.getId())){//如果ID是空为添加
            model.addAttribute("isAdd", true);
        }
        return "modules/web/yjQrcodesForm";
    }

    /**
     * 保存二维码
     */
    @RequiresPermissions(value={"web:yjQrcodes:add","web:yjQrcodes:edit"},logical=Logical.OR)
    @RequestMapping(value = "save")
    public String save(YjQrcodes yjQrcodes, Model model, RedirectAttributes redirectAttributes) throws Exception{
        if (!beanValidator(model, yjQrcodes)){
            return form(yjQrcodes, model);
        }

        // 重复检查
        List<YjQrcodes> list = yjQrcodesService.findList(yjQrcodes);
        if (!list.isEmpty()) {
            addMessage(model, "保存二维码失败: 二维码重复");
            return form(yjQrcodes, model);
        }

        //新增或编辑表单保存
        yjQrcodesService.save(yjQrcodes);//保存
        addMessage(redirectAttributes, "保存二维码成功");
        return "redirect:"+ Global.getAdminPath()+"/web/yjQrcodes/?repage";
    }

    /**
     * 删除二维码
     */
    @ResponseBody
    @RequiresPermissions("web:yjQrcodes:del")
    @RequestMapping(value = "delete")
    public AjaxJson delete(YjQrcodes yjQrcodes, RedirectAttributes redirectAttributes) {
        AjaxJson j = new AjaxJson();
        yjQrcodesService.delete(yjQrcodes);
        j.setMsg("删除二维码成功");
        return j;
    }

    /**
     * 批量删除二维码
     */
    @ResponseBody
    @RequiresPermissions("web:yjQrcodes:del")
    @RequestMapping(value = "deleteAll")
    public AjaxJson deleteAll(String ids, RedirectAttributes redirectAttributes) {
        AjaxJson j = new AjaxJson();
        String idArray[] =ids.split(",");
//        for(String id : idArray){
//            yjQrcodesService.delete(yjQrcodesService.get(id));
//        }

        // 检查是否有被使用的
        List<String> idsList = Arrays.asList(idArray);
        boolean isInUse = yjQrcodesService.isInUse(idsList);
        if (isInUse) {
            j.setSuccess(false);
            j.setMsg("二维码已被使用，删除失败");
            return j;
        }

        // 批量逻辑删除
        yjQrcodesService.batchDeleteByLogic(idsList);

        j.setMsg("删除二维码成功");
        return j;
    }

    /**
     * 批量生成二维码
     * @return
     */
    @ResponseBody
    @RequiresPermissions("web:yjQrcodes:batchCreateQrcode")
    @PostMapping(value = "batchCreateQrcode")
    public AjaxJson batchCreateQrcode() {
        return batchCreateQrcode(20);
    }

    /**
     * 批量生成二维码plus
     * @param total 二维码个数
     * @return
     */
    @ResponseBody
    @PostMapping(value = "batchCreateQrcodePlus")
    public AjaxJson batchCreateQrcodePlus(int total) {
        return batchCreateQrcode(total);
    }

    /**
     * 批量生成二维码
     * @param total 二维码数量 默认是20个
     * @return
     */
    private AjaxJson batchCreateQrcode(int total) {
        AjaxJson j = new AjaxJson();

        User currentUser = UserUtils.getUser();

        // 批量新增20个新二维码, 20是可配置的
        List<YjQrcodes> yjQrCodesList = new ArrayList<>();
        List<String> qrCodesList = new ArrayList<>();
        for (int i = 0; i < total; i++) {
            String qrcode = UUID.randomUUID().toString().replaceAll("-", "");

            YjQrcodes yjQrcodes = new YjQrcodes();
            yjQrcodes.setQrcode(qrcode);
            yjQrcodes.setCategory(CATEGORY_MAHJONGHALLROOM);
            yjQrcodes.setCreateBy(currentUser);
            yjQrcodes.setUpdateBy(currentUser);


            StringBuffer sb = new StringBuffer();
            sb.append(imgUrl).append(roomQrCodeFolder).append("/").append(qrcode).append(".png");
            yjQrcodes.setQrCodeFilePath(sb.toString());

            yjQrCodesList.add(yjQrcodes);
            qrCodesList.add(qrcode);
        }

        // 批量插入数据库
        yjQrcodesService.batchCreateQrcode(yjQrCodesList);

        // 批量生成文件
        qrCodesList.forEach(x -> {
            downloadQrcode(x);
        });

        j.setSuccess(true);
        j.setMsg("批量新增二维码成功");
        return j;
    }

    /**
     * 为没有图片的二维码补图片生成
     * @return
     */
    @ResponseBody
    @RequiresPermissions("web:yjQrcodes:list")
    @PostMapping(value="createNoImageQrCodes")
    public AjaxJson createNoImageQrCodes() {
        AjaxJson j = new AjaxJson();

        List<YjQrcodes> list = yjQrcodesService.fetchNoImageQrCodes();
        if (list == null || list.isEmpty()){
            j.setSuccess(true);
            j.setMsg("不存在没有生成图片的二维码");
            return j;
        }

        list.forEach(x -> {
            if (StringUtils.isNotBlank(x.getQrcode())) {
                downloadQrcode(x.getQrcode());
            }
        });

        j.setSuccess(true);
        j.setMsg("生成图片成功!");
        return j;
    }

    /**
     * 生成唯一二维码
     * @return
     */
    private String generateUniqueQrcode() {
        String s = UUID.randomUUID().toString();
        s = s.substring(0,8)+s.substring(9,13)+s.substring(14,18)+s.substring(19,23)+s.substring(24);
        return s.substring(0, 12);
    }

    /**
     * 生成并下载二维码
     * @param id
     * @param request
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "downloadQrcode")
    public AjaxJson downloadQrcode(String id, HttpServletRequest request) {
        AjaxJson j = new AjaxJson();

        if (StringUtils.isBlank(id)) {
            j.setSuccess(false);
            j.setMsg("id不能为空");
            return j;
        }

        // 获得qrcode
        YjQrcodes record = yjQrcodesService.get(id);
        if (record == null) {
            j.setSuccess(false);
            j.setMsg("二维码不存在或已被删除!");
            return j;
        }

        String qrcode = record.getQrcode();
        String qrcodeFilePath = record.getQrCodeFilePath();

        String fileName;
        String filePath;
        if (StringUtils.isNotBlank(qrcodeFilePath)) {
            fileName = qrcode + ".png";
            filePath = qrcodeFilePath;
        } else {
            // 生成小程序二维码 2021-03-31
            fileName = downloadQrcode(qrcode);

            StringBuffer sb = new StringBuffer();
            sb.append(imgUrl).append(roomQrCodeFolder).append("/").append(qrcode).append(".png");
            filePath = sb.toString();
        }

        j.put("filePath", filePath);
        j.put("fileName", fileName);
        j.setSuccess(true);
        return j;
    }

    /**
     * 下载普通二维码
     * @param qrcode
     * @return
     */
    private String downloadQrcode(String qrcode) {
        String fileName = qrcode + ".png";

        Path folderPath = Paths.get(imgFilesDirPath, roomQrCodeFolder);
        File dir = new File(folderPath.toString());
        if (!dir.exists()) {// 判断文件目录是否存在
            dir.mkdirs();
        }

        Path filePath = Paths.get(imgFilesDirPath, roomQrCodeFolder ,fileName);
        String destinationPath = filePath.toString();

        // 生成二维码图片
        String qrIconFilePath = Global.getUserfilesBaseDir() + Global.IMAGE_BASE_URL + "yaojiu-room-icon.png";
        String qrContent = roomQrcodeGeneratorPath + qrcode;
        String wordContent = qrcode;
        QrImage qrImage = new QrImage(qrContent, 430, 430, qrIconFilePath, 200, 100, 12, wordContent, destinationPath);
        ImgQrTool.createQrWithFontsAbove(qrImage);

        return fileName;
    }


    /**
     * 批量打包下载二维码
     * @param ids
     * @param response
     */
    @RequestMapping(value = "download", method=RequestMethod.POST)
    public void pListDownload(String ids, HttpServletResponse response) throws IOException {

        if (StringUtils.isBlank(ids)) {
            return;
        }

        String idArray[] =ids.split(",");
        List<YjQrcodes> list = yjQrcodesService.getQrCodesByIds(Arrays.asList(idArray));
        if (list == null || list.isEmpty()) {
            return;
        }

        pListDownload(list, response);
    }

    /**
     * 打包下载
     * @param list
     * @param response
     * @throws IOException
     */
    private void pListDownload(List<YjQrcodes> list, HttpServletResponse response) throws IOException {

        if (list == null || list.isEmpty()) { // 没有数据，无需下载
            return;
        }

        // 创建临时路径,存放压缩文件
        Path tempImgPath = Paths.get(imgFilesDirPath, tempImgFolder);
        File tempImgDir = new File(tempImgPath.toString());
        if (!tempImgDir.exists()) {
            tempImgDir.mkdirs();
        }

        //拼接下载默认名称并转为ISO-8859-1格式
        String now = DateUtils.formatDate(new Date(), "yyyyMMddHHmmss");

        String filePath;
        String fileName;
        int count = list.size();
        boolean deleteTempFile = false;
        if (count > 1) { // 有多张二维码，此时要打包下载
            filePath = makeupZipFile(list); // 打包压缩文件
            fileName = new String(("二维码-" + now + ".zip").getBytes(),"ISO-8859-1");
            deleteTempFile = true;
        } else {  // 只有一张二维码，直接下载即可
            YjQrcodes yjQrcodes = list.get(0);
            filePath = getQrcodeFilePath(yjQrcodes); // 二维码图片地址

            StringBuilder sb = new StringBuilder();
            sb.append(yjQrcodes.getQrcode()).append("-").append(now).append(".png");
            fileName = new String(sb.toString().getBytes(),"ISO-8859-1");
        }

        if (StringUtils.isBlank(filePath)) { // 没有文件，直接返回
            return;
        }

        // set header
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

        //该流不可以手动关闭,手动关闭下载会出问题,下载完成后会自动关闭
        ServletOutputStream outputStream = response.getOutputStream();
        FileInputStream inputStream = new FileInputStream(filePath);

        // 如果是SpringBoot框架,在这个路径
        // org.apache.tomcat.util.http.fileupload.IOUtils产品
        // 否则需要自主引入apache的 commons-io依赖
        // copy方法为文件复制,在这里直接实现了下载效果
        IOUtils.copy(inputStream, outputStream);

        // 关闭输入流
        inputStream.close();

        //下载完成之后，删掉这个临时文件
        if (deleteTempFile) {
            File tempFile = new File(filePath);
            tempFile.delete();
        }
    }

    /**
     * 组装zip包压缩文件
     * @param list
     * @return
     * @throws IOException
     */
    private String makeupZipFile(List<YjQrcodes> list) throws IOException {

        // 压缩输出流,包装流,将临时文件输出流包装成压缩流,将所有文件输出到这里,打成zip包
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        Path zipFilePath = Paths.get(imgFilesDirPath, tempImgFolder, uuid + ".zip");
        ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFilePath.toString()));

        for(int i = 0; i < list.size(); i++) {
            YjQrcodes yjQrcodes = list.get(i);
            String qrcode = yjQrcodes.getQrcode();
            if (StringUtils.isBlank(qrcode)) {
                continue;
            }

            String fileName = qrcode + ".png";
            Path filePath = Paths.get(imgFilesDirPath, roomQrCodeFolder ,fileName);
            File file = new File(filePath.toString());
            if (!file.exists()) {
                continue;
            }

            // 将文件压入zip
            fileToZip(filePath.toString(), zipOut);
        }

        zipOut.close();

        return zipFilePath.toString();
    }

    /**
     * 将文件压入zip包
     * @param filePath
     * @param zipOut
     * @throws IOException
     */
    public void fileToZip(String filePath, ZipOutputStream zipOut) throws IOException {
        // 需要压缩的文件
        File file = new File(filePath);
        // 获取文件名称,如果有特殊命名需求,可以将参数列表拓展,传fileName
        String fileName = file.getName();
        FileInputStream fileInput = new FileInputStream(filePath);
        // 缓冲
        byte[] bufferArea = new byte[1024 * 10];
        BufferedInputStream bufferStream = new BufferedInputStream(fileInput, 1024 * 10);
        // 将当前文件作为一个zip实体写入压缩流,fileName代表压缩文件中的文件名称
        zipOut.putNextEntry(new ZipEntry(fileName));
        int length = 0;
        // 最常规IO操作,不必紧张
        while ((length = bufferStream.read(bufferArea, 0, 1024 * 10)) != -1) {
            zipOut.write(bufferArea, 0, length);
        }
        //关闭流
        fileInput.close();
        // 需要注意的是缓冲流必须要关闭流,否则输出无效
        bufferStream.close();
        // 压缩流不必关闭,使用完后再关
    }

    /**
     * 获得单个二维码图片文件
     * @param yjQrcodes
     * @return
     */
    private String getQrcodeFilePath(YjQrcodes yjQrcodes) {
        String fileName = yjQrcodes.getQrcode() + ".png";
        Path filePath = Paths.get(imgFilesDirPath, roomQrCodeFolder ,fileName);

        File file = new File(filePath.toString());
        if (!file.exists()) { // 文件不存在的时候，生成之
            downloadQrcode(yjQrcodes.getQrcode());
        }

        return filePath.toString();
    }

}
